home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
CU Amiga Super CD-ROM 17
/
CU Amiga Magazine's Super CD-ROM 17 (1997)(EMAP Images)(GB)[!][issue 1997-12].iso
/
CUCD
/
Programming
/
DiceSource
/
src
/
dd
/
cexp.c
< prev
next >
Wrap
C/C++ Source or Header
|
1997-09-09
|
14KB
|
725 lines
/*
* (c)Copyright 1992-1997 Obvious Implementations Corp. Redistribution and
* use is allowed under the terms of the DICE-LICENSE FILE,
* DICE-LICENSE.TXT.
*/
/*
* CEXP.C
*/
#include "defs.h"
#include "dbug_protos.h"
Prototype long ParseExp(char *, short *, long);
Prototype void PushOp(short, short, short);
Prototype int TopOfOpStack(void);
Prototype int SecondOffOpStack(void);
Prototype void PushAtom(long, short);
Local int CombineOp(void);
Local int GetAtomStack(short *, long *);
Local int ParseCharConst(char *, long, long, long *);
Local int ParseInt(char *, long, long, long *);
Local int HexDig(char);
Local int OctDig(char);
Local short SymbolChar(short);
Local long ExtSymbol(unsigned char *, long, long);
#define MAXATOM 128
#define MAXOPER 128
#define CGTEQ 256
#define CGTGT 257
#define CLTEQ 258
#define CLTLT 259
#define CNOTEQ 260
#define CEQEQ 261
#define CSYM 262
#define CUMI 263
#define CUIND 264
#define CDEFINED 280
#define CANDAND 281
#define COROR 282
#define QBIN 4 /* binary operator, else unary */
#define LR 1 /* left to right, else */
#define RL 2 /* right to left */
#define BLR (LR|QBIN)
#define BRL (RL|QBIN)
#define XX 0
typedef struct Atom {
long Value;
short Undef;
short Reserved;
} Atom;
typedef struct Oper {
short Token;
short Pri;
short Type;
short Reserved;
} Oper;
static Atom AtomStack[MAXATOM];
static Oper OperStack[MAXOPER];
static short AtomIdx;
static short OperIdx;
static short BaseAtomIdx;
static short BaseOperIdx;
long ParseExp(char *buf, short *pundef, long max)
{
short unary = 1;
short i = 0;
short parens = 0;
short baseOperIdx;
short baseAtomIdx;
baseOperIdx = BaseOperIdx = OperIdx;
baseAtomIdx = BaseAtomIdx = AtomIdx;
while (i < max) {
short c = buf[i];
++i;
if (c == ' ' || c == 9 || c == '\n')
continue;
if (unary) { /* int, sym, !exp, ~exp (exp), *exp */
switch(c) {
case '*': /* indirection */
PushOp(CUIND, 140, RL);
break;
case '!':
case '~':
PushOp(c, 140, RL);
break;
case '-':
PushOp(CUMI, 140, RL);
break;
case '(':
++parens;
PushOp(c, 0, XX);
break;
default:
if (c >= '0' && c <= '9') {
long v;
i = ParseInt(buf, i - 1, max, &v);
PushAtom(v, 0);
unary = 0;
break;
}
if (SymbolChar(c)) {
short ni;
long v;
long *rptr;
--i;
ni = ExtSymbol(buf, i, max); // extract symbol
if (i + 2 == ni && (rptr = RegisterAddress(buf + i))) {
PushAtom(*rptr, 0);
unary = 0;
i = ni;
break;
}
else if (LookupSymLen(buf + i, ni-i, &v)) {
PushAtom(v, 0);
unary = 0;
i = ni;
break;
}
else if (LookupSymLen(addscore(buf + i), ni-i+1, &v)) {
PushAtom(v, 0);
unary = 0;
i = ni;
break;
}
else if (LookupSymLen(addat(buf + i), ni-i+1, &v)) {
PushAtom(v, 0);
unary = 0;
i = ni;
break;
}
i++;
}
#ifdef MYKE_REMOVED_THIS
/*
* NOTE, handles 'defined' by pushing unary op instead
* of atom.
*/
if (SymbolChar(c)) { /* SymbolChar() includes '0'-'9' */
short ni;
--i;
ni = ExtSymbol(buf, i, max); /* extract symbol */
if (ni - i == 7 && strncmp(buf + i, "defined", 7) == 0) {
PushOp(CDEFINED, 140, RL);
} else if (TopOfOpStack() == CDEFINED || SecondOffOpStack() == CDEFINED) {
Sym *sym = FindSymbol(buf + i, ni - i);
if (sym)
PushAtom(1, 0);
else
PushAtom(0, 1);
unary = 0;
} else {
Sym *sym = FindSymbol(buf + i, ni - i);
if (sym) {
short xundef;
long v;
v = ParseExp(sym->Text, &xundef, sym->TextLen);
BaseOperIdx = baseOperIdx;
BaseAtomIdx = baseAtomIdx;
PushAtom(v, xundef);
} else {
PushAtom(0, 1);
}
unary = 0;
}
i = ni;
break;
}
#endif
if (c == '\'') {
long v;
i = ParseCharConst(buf, i - 1, max, &v);
PushAtom(v, 0);
unary = 0;
break;
}
syntax:
ScrStatus(("*** syntax error"));
syntax2:
*pundef = 1;
AtomIdx = baseAtomIdx;
OperIdx = baseOperIdx;
return(0);
}
}
else { /* + - * / % & | ^ <= << < == != > >> >= */
unary = 1;
switch(c) {
case '+':
case '-':
PushOp(c, 120, BLR);
break;
case '*':
case '/':
case '%':
PushOp(c, 130, BLR);
break;
case '&':
if (i < max && buf[i] == '&') {
PushOp(CANDAND, 50, BLR);
++i;
} else {
PushOp(c, 60, BLR);
}
break;
case '^':
PushOp(c, 70, BLR);
break;
case '|':
if (i < max && buf[i] == '|') {
++i;
PushOp(COROR, 40, BLR);
} else {
PushOp(c, 80, BLR);
}
break;
case '<':
if (i < max) {
short d = buf[i];
if (d == '<') {
PushOp(CLTLT, 110, BLR);
++i;
break;
}
if (d == '=') {
PushOp(CLTEQ, 100, BLR);
++i;
break;
}
}
PushOp(c, 100, BLR);
break;
case '=':
if (i >= max || buf[i] != '=')
goto syntax;
PushOp(CEQEQ, 90, BLR);
++i;
break;
case '!':
if (i >= max || buf[i] != '=')
goto syntax;
PushOp(CNOTEQ, 90, BLR);
++i;
break;
case '>':
if (i < max) {
short d = buf[i];
if (d == '>') {
PushOp(CGTGT, 110, BLR);
++i;
break;
}
if (d == '=') {
PushOp(CGTEQ, 100, BLR);
++i;
break;
}
}
PushOp(c, 100, BLR);
break;
case ')':
unary = 0;
if (parens == 0) {
ScrStatus(("*** Too many close parens"));
goto syntax2;
}
--parens;
while ((c = TopOfOpStack()) && c != '(')
CombineOp();
if (c == 0)goto syntax;
CombineOp();
break;
default:
goto syntax;
}
}
}
while (TopOfOpStack() >= 0 && CombineOp() >= 0)
;
if (TopOfOpStack() >= 0)goto syntax;
{
long v;
if (GetAtomStack(pundef, &v) < 0)goto syntax;
if (GetAtomStack(NULL, NULL) >= 0)goto syntax; // shouldn't be anything left
AtomIdx = baseAtomIdx;
OperIdx = baseOperIdx;
/*ScrStatus(("*** RESULT %d undef=%d", v, *pundef));*/
return(v);
}
}
void PushOp(short token, short pri, short type)
{
if (pri) {
while (OperIdx > BaseOperIdx) {
Oper *op = OperStack + OperIdx - 1;
if (pri > op->Pri)
break;
if (pri == op->Pri && (type & RL))
break;
if (CombineOp() < 0) {
ScrStatus(("*** Syntax error"));
break;
}
}
}
if (OperIdx == MAXOPER) {
ScrStatus(("*** Expression too complex"));
return;
}
{
Oper *op = OperStack + OperIdx++;
op->Pri = pri;
op->Token = token;
op->Type = type;
}
}
int TopOfOpStack(void)
{
if (OperIdx <= BaseOperIdx)return(-1);
return((int)OperStack[OperIdx-1].Token);
}
int SecondOffOpStack(void)
{
if (OperIdx - 1 <= BaseOperIdx)return(-1);
return((int)OperStack[OperIdx-2].Token);
}
void PushAtom(long val, short isundef)
{
Atom *atom;
if (AtomIdx == MAXATOM) {
ScrStatus(("*** Expression too complex"));
return;
}
atom = AtomStack + AtomIdx++;
atom->Value = val;
atom->Undef = isundef;
}
static int CombineOp(void)
{
Oper *op;
Atom *a1, *a2;
Atom ar;
if (OperIdx <= BaseOperIdx)return(-1);
op = OperStack + --OperIdx;
if (AtomIdx <= BaseAtomIdx)return(-1);
a1 = AtomStack + --AtomIdx;
if (op->Type & QBIN) {
if (AtomIdx <= BaseAtomIdx)return(-1);
a2 = AtomStack + --AtomIdx;
}
if (op->Type & QBIN) {
ar.Undef = a1->Undef | a2->Undef;
switch(op->Token) {
case '+':
ar.Value = a2->Value + a1->Value;
break;
case '-':
ar.Value = a2->Value - a1->Value;
break;
case '*':
ar.Value = a2->Value * a1->Value;
break;
case '/':
if (a1->Value)ar.Value = a2->Value / a1->Value;
else ar.Undef = 1;
break;
case '%':
if (a1->Value)ar.Value = a2->Value % a1->Value;
else ar.Undef = 1;
break;
case '&':
ar.Value = a2->Value & a1->Value;
break;
case '|':
ar.Value = a2->Value | a1->Value;
break;
case '^':
ar.Value = a2->Value ^ a1->Value;
break;
case '<':
ar.Value = a2->Value < a1->Value;
break;
case CLTLT:
ar.Value = a2->Value << a1->Value;
break;
case CLTEQ:
ar.Value = a2->Value <= a1->Value;
break;
case CEQEQ:
ar.Value = a2->Value == a1->Value;
break;
case CNOTEQ:
ar.Value = a2->Value != a1->Value;
break;
case '>':
ar.Value = a2->Value > a1->Value;
break;
case CGTGT:
ar.Value = a2->Value >> a1->Value;
break;
case CGTEQ:
ar.Value = a2->Value >= a1->Value;
break;
case CANDAND:
if (a2->Value && a1->Value)
ar.Value = 1;
else
ar.Value = 0;
break;
case COROR:
if (a2->Undef == 0 && a2->Value) {
ar.Value = 1;
ar.Undef = 0;
} else if (a1->Undef == 0 && a1->Value) {
ar.Value = 1;
ar.Undef = 0;
} else {
ar.Value = 0;
}
break;
default:
ScrStatus(("*** fatal error parsing exp"));
break;
}
}
else {
ar.Undef = a1->Undef;
switch(op->Token) {
case '!':
ar.Value = !a1->Value;
break;
case '~':
ar.Value = ~a1->Value;
break;
case CUIND: /* indirect through memory */
if (a1->Value & 1) {
ar.Undef = 1;
} else {
ar.Value = *(long *)a1->Value;
}
break;
case CUMI: /* negate */
ar.Value = -a1->Value;
break;
case '(':
ar.Value = a1->Value;
break;
case CDEFINED:
ar.Undef = 0;
if (a1->Undef)
ar.Value = 0;
else
ar.Value = 1;
break;
default:
ScrStatus(("*** fatal error parsing exp"));
break;
}
}
AtomStack[AtomIdx++] = ar;
/*ScrStatus(("*** op %c %03x result %d (%d)", op->Token, op->Token, ar.Value, ar.Undef));*/
}
static int GetAtomStack(short *pundef, long *pv)
{
Atom *at;
if (AtomIdx <= BaseAtomIdx) {
if (pundef)*pundef = 1;
return(-1);
}
at = AtomStack + --AtomIdx;
if (pundef)*pundef = at->Undef;
if (pv)*pv = at->Value;
return(0);
}
static int ParseCharConst(char *buf, long i, long max, long *pv)
{
unsigned char c;
long v = 0;
if (buf[i] != '\'')
return(0);
++i;
while (i < max && (c = buf[i]) != '\'') {
++i;
if (c == '\\' && i < max) {
c = buf[i++];
switch(c) {
case 'a':
c = 7;
break;
case 'b':
c = 8;
break;
case 'f':
c = 'f'&0x1F;
break;
case 'n':
c = 10;
break;
case 'r':
c = 13;
break;
case 't':
c = 9;
break;
case 'v':
c = 11;
break;
case 'x':
{
short n;
short r = 0;
short cnt = 2;
while (cnt && (n = HexDig(c)) > 0) {
r = (r << 4) + n;
c = buf[i++];
--cnt;
}
if (cnt)
--i;
c = r;
}
break;
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
{
short cnt;
short r;
short n;
for (r = cnt = 0; cnt < 3 && (n = OctDig(c)) >= 0; ++cnt) {
r = (r << 3) + n;
c = buf[i++];
}
--i;
c = r;
}
break;
default:
c = buf[i];
break;
}
}
v = (v << 8) | c;
}
*pv = v;
if (i < max) ++i; /* skip closing single quote */
else ScrStatus(("*** unterminated char const"));
return(i);
}
/*
* 0xhex
* 0octal
* 1-9decimal
*/
static int ParseInt(char *buf, long i, long max, long *pv)
{
char c;
long v = 0;
if (i < max && buf[i] == '0') {
++i;
if (i < max && (buf[i] == 'x' || buf[i] == 'X')) { /* hex */
short n;
++i;
while (i < max && (n = HexDig(buf[i])) >= 0) {
v = (v << 4) + n;
++i;
}
}
else { /* oct */
short n;
while (i < max && (n = OctDig(buf[i])) >= 0) {
v = (v << 3) + n;
++i;
}
}
}
else {
while (i < max && (c = buf[i]) >= '0' && c <= '9') { /* dec */
v = v * 10 + c - '0';
++i;
}
}
while ((c = buf[i]) == 'L' || c == 'l' || c == 'U' || c == 'u')++i;
// if a . follows the number, its a line number; so find the
// address associated with it
if((buf[i] == '.') && (CurDisplay->ds_DisplayMode <= DISPLAY_LONGS)) {
ULONG address, line ,info[2];
i++;
address = CurDisplay->ds_WindowTop;
line = 0;
CurrentMixedLine(&address,&line,info);
while(info[1] < v) {
NextMixedLine(&address,&line,info);
}
v = address;
}
*pv = v;
return(i);
}
static int HexDig(char c)
{
if (c >= '0' && c <= '9')return (c - '0');
if (c >= 'a' && c <= 'f')c = c + ('A' - 'a');
if (c >= 'A' && c <= 'F')return (c + (10 - 'A'));
return(-1);
}
static int OctDig(char c)
{
if (c >= '0' && c <= '7')return (c - '0');
return(-1);
}
/*
* Random support
*/
short SymbolChar(short c)
{
if (c >= '0' && c <= '9')return(1);
if (c >= 'a' && c <= 'z')return(1);
if (c >= 'A' && c <= 'Z')return(1);
if (c == '_' || c == '@')return(1);
return(0);
}
long ExtSymbol(unsigned char *base, long i, long max)
{
long b = i;
while (i < max && SymbolChar(base[i]))++i;
return(i);
}
#ifdef MYKE_REMOVED_THIS
typedef struct Sym {
char *Name;
char *Text;
long TextLen;
} Sym;
Local Sym *FindSymbol(char *, short);
Sym *FindSymbol(char *name, short nameLen)
{
static Sym SymAry[] = {
{ "a", "b+3" , 3 },
{ "b", "4" , 1 }
};
Sym *sym;
for (sym = SymAry; sym < SymAry + (sizeof(SymAry)/sizeof(SymAry[0])); ++sym) {
if (strlen(sym->Name) == nameLen && strnicmp(name, sym->Name, nameLen) == 0)
return(sym);
}
return(NULL);
}
#endif